using System;
using System.Windows;
using System.Windows.Controls;

using Microsoft.Practices.Composite.Presentation.Events;
using Microsoft.Practices.Unity;

using Supremacy.Annotations;
using Supremacy.Client.Commands;
using Supremacy.Client.Events;
using Supremacy.Resources;

using System.Linq;

namespace Supremacy.Client.Views
{
    public abstract class GameScreenViewBase : Control, IAnimationsHost
    {
        #region Dependency Properties
        public static readonly DependencyProperty ClientContextProperty;
        #endregion

        #region Constructors and Finalizers
        static GameScreenViewBase()
        {
            ClientContextProperty = DependencyProperty.Register(
                "ClientContext",
                typeof(IClientContext),
                typeof(UIElement),
                new FrameworkPropertyMetadata(
                    null,
                    FrameworkPropertyMetadataOptions.Inherits));
        }
        #endregion

        #region Properties and Indexers
        public IClientContext ClientContext
        {
            get { return GetValue(ClientContextProperty) as IClientContext; }
            set { SetValue(ClientContextProperty, value); }
        }
        #endregion

        #region Public and Protected Methods
        public static IClientContext GetClientContext(DependencyObject element)
        {
            if (element == null)
                return null;
            return element.GetValue(ClientContextProperty) as IClientContext;
        }

        public static void SetClientContext(DependencyObject element, IClientContext value)
        {
            if (element == null)
                throw new ArgumentNullException("element");
            element.SetValue(ClientContextProperty, value);
        }
        #endregion

        protected void PauseAnimations()
        {
            foreach (var animationsHost in this.FindVisualDescendantsByType<DependencyObject>().OfType<IAnimationsHost>())
            {
                try { animationsHost.PauseAnimations(); }
                catch {}
            }
        }

        #region Implementation of IAnimationsHost

        void IAnimationsHost.PauseAnimations()
        {
            this.PauseAnimations();
        }

        void IAnimationsHost.ResumeAnimations()
        {
            this.ResumeAnimations();
        }

        void IAnimationsHost.StopAnimations()
        {
            this.StopAnimations();
        }

        #endregion

        protected void ResumeAnimations()
        {
            foreach (var animationsHost in this.FindVisualDescendantsByType<DependencyObject>().OfType<IAnimationsHost>())
            {
                try { animationsHost.ResumeAnimations(); }
                catch {}
            }
        }

        protected void StopAnimations()
        {
            foreach (var animationsHost in this.FindVisualDescendantsByType<DependencyObject>().OfType<IAnimationsHost>())
            {
                try { animationsHost.ResumeAnimations(); }
                catch {}
            }
        }
    }

    public abstract class GameScreenView<TPresentationModel> : GameScreenViewBase, IGameScreenView<TPresentationModel>
        where TPresentationModel : class
    {
        #region Fields
        private readonly IUnityContainer _container;
        private readonly IPlayerOrderService _playerOrderService;
        private readonly INavigationCommandsProxy _navigationCommands;
        private readonly IResourceManager _resourceManager;

        private bool _isActive;
        #endregion

        #region Constructors and Finalizers
        protected GameScreenView([NotNull] IUnityContainer container)
        {
            if (container == null)
                throw new ArgumentNullException("container");
            
            _container = container;
            _playerOrderService = _container.Resolve<IPlayerOrderService>();
            _navigationCommands = _container.Resolve<INavigationCommandsProxy>();
            _resourceManager = _container.Resolve<IResourceManager>();

            this.IsVisibleChanged += OnIsVisibleChanged;
        }
        #endregion

        #region Properties and Indexers
        protected IUnityContainer Container
        {
            get { return _container; }
        }

        protected INavigationCommandsProxy NavigationCommands
        {
            get { return _navigationCommands; }
        }

        protected IResourceManager ResourceManager
        {
            get { return _resourceManager; }
        }
        #endregion

        #region Public and Protected Methods
        protected virtual void OnHide() {}

        protected virtual void OnIsActiveChanged()
        {
            var handler = this.IsActiveChanged;
            if (handler != null)
                handler(this, EventArgs.Empty);
        }

        protected virtual void OnShow() {}
        #endregion

        #region Implementation of IActiveAware
        public event EventHandler IsActiveChanged;

        public bool IsActive
        {
            get { return _isActive; }
            set
            {
                if (Equals(_isActive, value))
                    return;
                _isActive = value;
                UpdateCommands();
                OnIsActiveChanged();
            }
        }
        #endregion

        #region Implementation of IGameScreenView
        public TPresentationModel Model
        {
            get { return this.DataContext as TPresentationModel; }
            set { this.DataContext = value; }
        }

        protected IPlayerOrderService PlayerOrderService
        {
            get { return _playerOrderService; }
        }

        public virtual void OnCreated()
        {
            OnCreatedOverride();
            RegisterCommandAndEventHandlers();
        }

        public virtual void OnDestroyed()
        {
            UnregisterCommandAndEventHandlers();
            OnDestroyedOverride();
        }
        #endregion

        #region Protected Methods
        protected virtual void RegisterCommandAndEventHandlers() {}
        protected virtual void UnregisterCommandAndEventHandlers() {}

        protected virtual void OnCreatedOverride() {}
        protected virtual void OnDestroyedOverride() {}

        protected virtual void UpdateCommands() {}
        #endregion

        #region Private Methods
        private void OnHideCore()
        {
            ClientEvents.TurnEnded.Unsubscribe(OnTurnEnded);
            ClientEvents.TurnStarted.Unsubscribe(OnTurnStarted);
            PauseAnimations();
            OnHide();
        }

        private void OnTurnStarted(ClientEventArgs obj)
        {
            OnTurnStarted();
            ResumeAnimations();
        }

        protected virtual void OnTurnStarted() {}

        private void OnTurnEnded(ClientEventArgs obj)
        {
            PauseAnimations();
        }

        private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (IsVisible)
                OnShowCore();
            else
                OnHideCore();
        }

        private void OnShowCore()
        {
            ClientEvents.TurnEnded.Subscribe(OnTurnEnded, ThreadOption.UIThread);
            ClientEvents.TurnStarted.Subscribe(OnTurnStarted, ThreadOption.UIThread);
            ResumeAnimations();
            OnShow();
        }
        #endregion
    }
}